package moodish.dummy;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.LinkedList;

import moodish.comm.ClientSideMessage;
import moodish.comm.ListenConnectionsFromClient;
import moodish.comm.ListenMessagesFromClient;
import moodish.comm.ServerComm;
import moodish.comm.ServerSideMessage;
import moodish.message.MessageFromClient;
import moodish.message.MessageFromServer;

/**
 * Class that implements the interface {@link moodish.comm.ServerComm}
 * @author Diogo Medeiros
 * @version 1 
 */

public class ServerCommDummy implements ServerComm {
	private final int PORT_NUMBER = 8010;
	private Socket clientSocket;
	private LinkedList<MessageFromClient> messageClients = new LinkedList<MessageFromClient>();
	private HashMap<String, ListenMessagesFromClient> connectedClients;
	private ServerSocket serverSocket;
	
	@Override
	public void start() {
		try {
			serverSocket = new ServerSocket(PORT_NUMBER);
			messageClients = new LinkedList<MessageFromClient>();
			connectedClients = new HashMap<String,ListenMessagesFromClient>();
		} catch (IOException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		
			ListenConnectionsFromClient listenConnection = new ListenConnectionsFromClient(clientSocket, serverSocket, this);
		    Thread serverThread = new Thread(listenConnection);
	        serverThread.start();
	}

	@Override
	public boolean hasNextMessage() {
		synchronized(messageClients)
		{
				if (messageClients.size()>0)
				{
					return true;
					
				}
				else
				{
					return false;
				}
			}
	}

	@Override
	public ServerSideMessage getNextMessage() {
		synchronized(messageClients)
		{
			while(!hasNextMessage())
			{
				try {
					messageClients.wait();
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			return messageClients.poll();
		}
	
	}

	@Override
	public void sendNewFriendship(String toNickname, String newFriendship) {
		try {
			
			connectedClients.get(toNickname).getToClient().writeObject(
							new MessageFromServer(
									ClientSideMessage.Type.FRIENDSHIP,
									ClientSideMessage.SERVER, toNickname,
									newFriendship));
			connectedClients.get(toNickname).getToClient().flush();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	@Override
	public void sendError(String toNickname, String error) {
		try {
			connectedClients.get(toNickname).getToClient().writeObject(
					new MessageFromServer(ClientSideMessage.Type.ERROR,
							ClientSideMessage.SERVER, toNickname, error));
			connectedClients.get(toNickname).getToClient().flush();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	@Override
	public boolean clientIsConnected(String nickname) {
		return connectedClients.containsKey(nickname);
	}

	@Override
	public void sendClientConnected(String toNickname, String userConnected) {
		try {
			connectedClients.get(toNickname).getToClient().writeObject(
							new MessageFromServer(
									ClientSideMessage.Type.CONNECTED,
									ClientSideMessage.SERVER, toNickname,
									userConnected));
			connectedClients.get(toNickname).getToClient().flush();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	@Override
	public void sendClientDisconnected(String toNickname,
			String userDisconnected) {
		try {
			connectedClients.get(toNickname).getToClient().writeObject(
					new MessageFromServer(ClientSideMessage.Type.DISCONNECTED,
							ClientSideMessage.SERVER, toNickname,
							userDisconnected));
			connectedClients.get(toNickname).getToClient().flush();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	@Override
	public void disconnectClient(String nickname) {
		try {
		synchronized(connectedClients)
		{
			connectedClients.get(nickname).getSocket().close();
			connectedClients.remove(nickname);
		}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		
	}

	@Override
	public void sendMoodishMessage(String fromNicename, String toNickname,
			String message) {
		try {
			connectedClients.get(toNickname).getToClient().writeObject(
					new MessageFromServer(
							ClientSideMessage.Type.MOODISH_MESSAGE,
							fromNicename, toNickname, message));
			connectedClients.get(toNickname).getToClient().flush();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	@Override
	public void sendNewUnfriendship(String toNickname, String newFriendship) {
		try {
			connectedClients.get(toNickname).getToClient().writeObject(
							new MessageFromServer(
									ClientSideMessage.Type.UNFRIENDSHIP,
									ClientSideMessage.SERVER, toNickname,
									newFriendship));
			connectedClients.get(toNickname).getToClient().flush();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}
	
	/**
	 * Add a message received from a client to a queue (LinkedList)
	 * @param message             Message received from a client to be added to the LinkedList
	 *
	 */
	public void addMessage(MessageFromClient message)
	{
		synchronized(messageClients)
		{
			messageClients.add(message);
			messageClients.notifyAll();
			
		}
	}
	
	/**
	 * When a Client connects to the server this method add the connected client to a HashMap until he disconnects.
	 * 
	 * @param username                    Username of the client. This is the key of the HashMap
	 * @param connected                   This is the thread when this specific client communicate with the server.
	 * 
	 */
	public void addConnectedClient(String username, ListenMessagesFromClient connected)
	{
		synchronized(connectedClients)
		{
			if (connectedClients.containsKey(username))
			{
				try {
					connected.getToClient().writeObject(new MessageFromServer(
										ClientSideMessage.Type.ERROR,
										ClientSideMessage.SERVER, username,
										"Nickname in use. Use other."));
				} catch (IOException e) {
					try {
						connected.getSocket().close();
					} catch (IOException e1) {
						// TODO Auto-generated catch block
						e1.printStackTrace();
					}
				}
			}
			else
			{
				connectedClients.put(username, connected);
			}
		}
	}
}
